package org.oslims.server.service.impl;

import java.util.List;

import net.sf.gilead.gwt.GwtConfigurationHelper;
import net.sf.gilead.gwt.PersistentRemoteService;

import org.hibernate.Session;
import org.oslims.client.service.AnalysisResultService;
import org.oslims.domain.AbstractSample;
import org.oslims.domain.Analysis;
import org.oslims.domain.AnalysisResult;
import org.oslims.domain.BooleanParameterResult;
import org.oslims.domain.DateParameterResult;
import org.oslims.domain.NumberParameterResult;
import org.oslims.domain.Parameter;
import org.oslims.domain.ParameterResult;
import org.oslims.domain.TextParameterResult;
import org.oslims.server.Util.StateHelper;
import org.oslims.server.dao.AbstractSampleDao;
import org.oslims.server.dao.AnalysisDao;
import org.oslims.server.dao.AnalysisResultDao;
import org.oslims.server.dao.ParameterResultDao;
import org.oslims.server.dao.hbm.HbmAbstractSampleDao;
import org.oslims.server.dao.hbm.HbmAnalysisDao;
import org.oslims.server.dao.hbm.HbmAnalysisResultDao;
import org.oslims.server.dao.hbm.HbmParameterResultDao;
import org.oslims.server.dao.util.HibernateUtil;

public class AnalysisResultServiceImpl extends PersistentRemoteService implements AnalysisResultService {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4464139023786525836L;

	AnalysisResultDao analysisResultDao;
	AnalysisDao analysisDao;
	AbstractSampleDao abstractSampleDao;
	ParameterResultDao parameterResultDao;

	public AnalysisResultServiceImpl() {
		analysisResultDao = new HbmAnalysisResultDao();
		abstractSampleDao = new HbmAbstractSampleDao();
		parameterResultDao = new HbmParameterResultDao();
		analysisDao = new HbmAnalysisDao();

		net.sf.gilead.core.hibernate.HibernateUtil hibernateUtil = new net.sf.gilead.core.hibernate.HibernateUtil(HibernateUtil.getSessionFactory());
		setBeanManager(GwtConfigurationHelper.initGwtStatelessBeanManager(hibernateUtil));
	}

	@Override
	public void removeAnalysisResult(AnalysisResult analysisResult) {

		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try {
			analysisResultDao.setSession(session);
			analysisResultDao.makeTransient(analysisResult);
			session.getTransaction().commit();
		} catch (RuntimeException e) {
			session.getTransaction().rollback();
			throw e;
		} finally {
			session.close();
		}
	}

	@Override
	public void saveNewAnalysisResults(List<AnalysisResult> analysisResults) {

		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try {
			analysisResultDao.setSession(session);
			abstractSampleDao.setSession(session);
			analysisDao.setSession(session);
			parameterResultDao.setSession(session);

			for (AnalysisResult analysisResult : analysisResults) {
				analysisResultDao.makePersistent(analysisResult);
				AbstractSample s = analysisResult.getSample();

				// Change the state of the sample to in analyzing of the sample
				// is recieved or prepared
				if (!s.getState().equals("Not Recieved") && !s.getState().equals("Not Prepared")) {
					s.setState("In Analyzing");
					abstractSampleDao.makePersistent(s);
				}

				// Fetch the associated parameters for the analysis
				Analysis analysis = analysisDao.findById(analysisResult.getAnalysis().getId(), true);

				for (Parameter parameter : analysis.getDeterminedParameter()) {
					ParameterResult paRes = null;

					if (parameter.getType().equals("Number"))
						paRes = new NumberParameterResult();
					if (parameter.getType().equals("Text"))
						paRes = new TextParameterResult();
					if (parameter.getType().equals("Boolean"))
						paRes = new BooleanParameterResult();
					if (parameter.getType().equals("Date"))
						paRes = new DateParameterResult();
					if (paRes == null)
						throw new IllegalArgumentException("Parametertype not defined: " + parameter.getType());

					paRes.setAnalysisResult(analysisResult);
					paRes.setParameter(parameter);
					paRes.setState("In Analyzing");
					parameterResultDao.makePersistent(paRes);
				}
			}
			session.getTransaction().commit();
		} catch (RuntimeException e) {
			session.getTransaction().rollback();
			throw e;
		} finally {
			session.close();
		}

	}

	@Override
	public void saveOrUpdateAnalysisResult(AnalysisResult analysisResult) {
		Session session = HibernateUtil.getSession();
		session.beginTransaction();
		try {
			analysisResultDao.setSession(session);
			analysisResultDao.makePersistent(analysisResult);
			session.getTransaction().commit();
		} catch (RuntimeException e) {
			session.getTransaction().rollback();
			throw e;
		} finally {
			session.close();
		}

	}

	@Override
	public List<AnalysisResult> getAnalysisResultsBySample(AbstractSample abstractSample) {
		Session session = HibernateUtil.getSession();
		session.beginTransaction();

		analysisResultDao.setSession(session);

		List<AnalysisResult> result = analysisResultDao.findBySample(abstractSample);

		session.close();

		return result;

	}

	@Override
	public List<AnalysisResult> getAnalysisResultsBySampleAndAnalysisAndState(AbstractSample abstractSample, Analysis analysis, String state) {
		Session session = HibernateUtil.getSession();
		session.beginTransaction();

		analysisResultDao.setSession(session);

		List<AnalysisResult> result = analysisResultDao.findBySampleAndAnalysisAndState(abstractSample, analysis, state);

		session.close();

		return result;
	}

	@Override
	public List<AnalysisResult> getAnalysisResultsBySampleAndState(AbstractSample abstractSample, String state) {
		Session session = HibernateUtil.getSession();
		session.beginTransaction();

		analysisResultDao.setSession(session);

		List<AnalysisResult> result = analysisResultDao.findBySampleAndState(abstractSample, state);

		session.close();

		return result;
	}

	@Override
	public void validateAnalysisResults(List<AnalysisResult> analysisResults) {
		if (analysisResults.size() == 0) {
			throw new IllegalArgumentException("No results provided to validate");
		}

		String newState = analysisResults.get(0).getState();
		List<String> lowerStates = StateHelper.getLowerStates(newState);

		Session session = HibernateUtil.getSession();

		session.beginTransaction();

		parameterResultDao.setSession(session);
		analysisResultDao.setSession(session);
		abstractSampleDao.setSession(session);

		for (AnalysisResult ar : analysisResults) {

			analysisResultDao.makePersistent(ar);

			for (ParameterResult pr : ar.getParameterResults()) {
				pr.setState(newState);
				parameterResultDao.makePersistent(pr);
			}

			Boolean inLowerState = false;

			// Check if we can change the state of the sample
			List<String> sampleStates = analysisResultDao.getAnalysisStatesForSample(ar.getSample().getCode());

			for (String s : lowerStates) {
				if (sampleStates.contains(s)) {
					inLowerState = true;
					break;
				}
			}

			if (!inLowerState) {
				// Yes we can
				ar.getSample().setState(ar.getState());
				abstractSampleDao.makePersistent(ar.getSample());
			}

		}

		session.getTransaction().commit();

		session.flush();
		session.close();

	}

}
